https://cryptohack.org/challenges/general/
他說我們已經掌握了各種編碼的竅門,而在這題我們需要學會去自動化這個過程。題目問我們能通過這題的 100 個關卡來獲得 flag 嗎?
13377.py:
#!/usr/bin/env python3
# 匯入必要的模組和函數
from Crypto.Util.number import bytes_to_long, long_to_bytes
from utils import listener # Cryptohack 提供的伺服器端模組,不是 Python 的內建模組
import base64
import codecs # 用於 Rot13 編碼/解碼
import random
FLAG = "crypto{????????????????????}"
# 定義編碼方式列表
ENCODINGS = [
"base64",
"hex",
"rot13",
"bigint",
"utf-8",
]
# 讀取字典檔中的單詞列表
with open('/usr/share/dict/words') as f:
WORDS = [line.strip().replace("'", "") for line in f.readlines()]
# 定義 Challenge 類別
class Challenge():
def __init__(self):
self.challenge_words = "" # 用於儲存當前挑戰的單詞
self.stage = 0 # 用於追踪挑戰的階段
# 創建挑戰關卡
def create_level(self):
self.stage += 1 # 更新階段
# 隨機選擇 3 個單詞並使用底線(_)連接
self.challenge_words = "_".join(random.choices(WORDS, k=3))
# 隨機選擇一種編碼方式
encoding = random.choice(ENCODINGS)
# 根據選定的編碼方式對單詞進行編碼
if encoding == "base64":
encoded = base64.b64encode(self.challenge_words.encode()).decode()
elif encoding == "hex":
encoded = self.challenge_words.encode().hex()
elif encoding == "rot13":
encoded = codecs.encode(self.challenge_words, 'rot_13')
elif encoding == "bigint":
encoded = hex(bytes_to_long(self.challenge_words.encode()))
elif encoding == "utf-8":
encoded = [ord(b) for b in self.challenge_words]
# 返回包含編碼類型、編碼結果的字典
return {"type": encoding, "encoded": encoded}
# 處理使用者輸入的挑戰函數,使用者的輸入必須是 JSON 編碼格式
def challenge(self, your_input):
if self.stage == 0:
return self.create_level() # 如果是第一階段,建立新挑戰關卡
elif self.stage == 100:
self.exit = True # 如果當前挑戰階段=100 時,設定退出
return {"flag": FLAG} # 返回 flag
# 如果解碼後的結果與原始單詞相符,建立下一個挑戰關卡
if self.challenge_words == your_input["decoded"]:
return self.create_level()
# 如果解碼失敗,返回錯誤信息
return {"error": "Decoding fail"}
# 將 Challenge 類別注入到內建函數中,讓它能夠在本地運行
import builtins; builtins.Challenge = Challenge # 參考 Cryptohack FAQ 中的解釋
# 啟動伺服器,監聽端口 13377
listener.start_server(port=13377)
稍微了解一下原始碼的運行可以發現,它會從單字庫隨機選取三個單字,並從五種加密方式隨機選擇一種進行相對應的加密。如果我們返回的解碼結果與原始單詞相符,進入下一個挑戰關卡。當總共進行100次關卡後就會返回flag。
建立一個decode函式,讓它根據輸入的加密類型進行相對應的解密程序。
在還沒有收到flag之前無限次進行接收加密後的訊息並發送解密後的訊息。
當收到flag後,將其print出來。
from pwn import * # pip install pwntools
from Crypto.Util.number import*
import json
import base64
import codecs
r = remote('socket.cryptohack.org', 13377, level = 'debug')
def json_recv():
line = r.recvline()
return json.loads(line.decode())
def json_send(hsh):
request = json.dumps(hsh).encode()
r.sendline(request)
def decode(type,en):
if type == "base64":
decoded= base64.b64decode(en).decode()
elif type == "hex":
decoded= bytes.fromhex(en).decode()
elif type == "rot13":
decoded = codecs.encode(en, 'rot_13') # rot13的解密與加密相同
elif type == "bigint":
decoded = long_to_bytes(int(en, 16)).decode()
elif type == "utf-8":
decoded = "".join([chr(b) for b in en])
return decoded
flag=True
while(flag):
received = json_recv()
if "flag" in received:
print("#############################")
print("flag: ")
print(received["flag"])
flag=False
break
to_send = {
"decoded": decode(received["type"], received["encoded"])
}
json_send(to_send)
crypto{3nc0d3_d3c0d3_3nc0d3}
順便介紹一下凱薩密碼與ROT13密碼
* 凱薩密碼的一個特殊變種,只使用固定位移量13。
* 是一個對稱加密系統,因為位移13之後的結果再位移13次就會回到原來的文本。
* 將密文再次加密就會得到明文。
* ROT13 經常用於網路論壇上隱藏敏感或劇透的資訊。
解題過程:
昨天沒解完的,解到了今天,在循環接收與發送訊息的那部份卡了很久。明天應該會把AES的下一題解出來,之後就會寫其他平台比較輕鬆的邊複習之前所學邊解題的紀錄。因為腦袋好累...